/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package io.iec.edp.caf.rpc.extension;

import io.iec.edp.caf.boot.context.CAFContext;
import io.iec.edp.caf.common.JSONSerializer;
import io.iec.edp.caf.commons.utils.SpringBeanUtils;
import io.iec.edp.caf.core.context.ICAFContextService;
import io.iec.edp.caf.core.session.ICafSessionService;
import io.iec.edp.caf.rpc.api.support.ConstanceVarible;
import io.iec.edp.caf.rpc.api.entity.RpcContext;
import io.iec.edp.caf.rpc.api.spi.RpcContextResolver;
import io.iec.edp.caf.rpc.extension.context.SessionTransmitter;
import io.iec.edp.caf.tenancy.api.ITenantRouteService;
import io.iec.edp.caf.tenancy.api.ITenantService;
import io.iec.edp.caf.tenancy.api.context.RequestTenantContextHolder;
import io.iec.edp.caf.tenancy.api.context.RequestTenantContextInfo;
import io.iec.edp.caf.tenancy.api.entity.TenancyMode;
import io.iec.edp.caf.tenancy.api.exception.TenantNotFoundException;
import lombok.extern.slf4j.Slf4j;
import lombok.var;
import org.springframework.util.StringUtils;

import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;

@Slf4j
public class RpcContextResolverImpl implements RpcContextResolver {

    @Override
    public boolean resolveIsolated(Integer requsetTenantId, String su){
        ICAFContextService cafContextService = SpringBeanUtils.getBean(ICAFContextService.class);
        //tenant not same,neet isolated;
        var check = requsetTenantId!=null && requsetTenantId!= cafContextService.getTenantId();
        ITenantService tenant = SpringBeanUtils.getBean(ITenantService.class);
        var defaultAppInstance = "pg01";
        if(requsetTenantId==null || su == null || su.length()==0){
            log.info("tenant and su is null can not sure isolated，return default false");
            return false;
        }else{
            var curSuDB = tenant.getDBConnInfo(requsetTenantId,defaultAppInstance, CAFContext.current.getCurrentSU());
            var targetSuDB = tenant.getDBConnInfo(requsetTenantId,defaultAppInstance,su);
            // current su and target su dbconnection（not same database） not same need isolated
            var check2 = curSuDB!=null && targetSuDB!=null && curSuDB.getId()!=targetSuDB.getId();
            return check || check2;

        }
    }

    @Override
    public Integer resolveRequestTargetTenantId(String msu, HashMap<String, String> context) {
        ITenantService tenantService = SpringBeanUtils.getBean(ITenantService.class);
        ITenantRouteService tenantRouteService = SpringBeanUtils.getBean(ITenantRouteService.class);;
        if (tenantService.getTenancyMode() != TenancyMode.group)
            return null;

        context = context == null ? new HashMap<>() : context;
        String tenantIdString = context.get(ConstanceVarible.ROUTE_TENANTID);
        if (tenantIdString != null) {
            return Integer.valueOf(tenantIdString);
        } else {
            String tenantDim1 = context.get(ConstanceVarible.ROUTE_FIRSTDIMENSION_KEY);
            String tenantDim2 = context.get(ConstanceVarible.ROUTE_SECONDDIMENSION_KEY);
            if (!StringUtils.isEmpty(tenantDim1)) {
                try {
                    return tenantRouteService.route(msu, tenantDim1, tenantDim2);
                } catch (TenantNotFoundException e) {
                    log.error(String.format("tenant route failed su：%s first dimension：%s ,second dimension：%s", msu, tenantDim1, tenantDim2));
                }
            }

            //get requset header tenant if set
            RequestTenantContextInfo contextInfo = RequestTenantContextHolder.get();
            return contextInfo == null ? null : contextInfo.getTenantId();
        }
    }

    @Override
    public void validateRpcContext(RpcContext context) {
        var sessionsrv = SpringBeanUtils.getBean(ICafSessionService.class);
        var sessionid = (String) context.getContext(SessionTransmitter.SESSIONID);

        if(log.isDebugEnabled() && sessionid!=null && sessionid.length()>0){
            var session = sessionsrv.findById(sessionid);
            log.debug("current sessionid:"+ sessionid);
            log.debug("current sessionid isExpired:"+ (!"".equals(sessionid) ? sessionsrv.isExpired(sessionid) : true));
            log.debug("current session :"+ session!=null?JSONSerializer.serialize(session):"[session is null]");
        }
    }
}
